import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';

export class MybatisDefinitionProvider implements vscode.DefinitionProvider {
    async provideDefinition(
        document: vscode.TextDocument,
        position: vscode.Position,
        token: vscode.CancellationToken
    ): Promise<vscode.Location | vscode.Location[] | undefined> {
        const fileName = document.fileName;
        const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri);
        
        if (!workspaceFolder) {
            return undefined;
        }

        // 获取光标所在的单词
        const wordRange = document.getWordRangeAtPosition(position);
        if (!wordRange) {
            return undefined;
        }
        const word = document.getText(wordRange);

        console.log(`Searching definition for: ${word}`);

        // 判断文件类型
        if (fileName.endsWith('.java')) {
            return this.handleJavaFile(document, word, workspaceFolder);
        } else if (fileName.endsWith('.xml')) {
            return this.handleXmlFile(document, word, workspaceFolder);
        }

        return undefined;
    }

    private async handleJavaFile(
        document: vscode.TextDocument,
        word: string,
        workspaceFolder: vscode.WorkspaceFolder
    ): Promise<vscode.Location | undefined> {
        // 从Java文件中获取接口名称
        const interfaceName = this.getInterfaceName(document);
        if (!interfaceName) {
            console.log(`Could not determine interface name from Java file`);
            return undefined;
        }

        console.log(`Found interface name: ${interfaceName}`);

        // 构建可能的XML文件路径
        const possibleXmlPaths = this.getPossibleXmlPaths(workspaceFolder.uri.fsPath, interfaceName);
        console.log(`Searching in possible XML paths: ${possibleXmlPaths.join(', ')}`);
        
        // 在XML文件中查找对应的statement
        for (const xmlPath of possibleXmlPaths) {
            if (fs.existsSync(xmlPath)) {
                console.log(`Checking XML file: ${xmlPath}`);
                const xmlContent = fs.readFileSync(xmlPath, 'utf8');
                const statementPosition = this.findStatementInXml(xmlContent, word);
                if (statementPosition) {
                    console.log(`Found statement at line ${statementPosition.line}, char ${statementPosition.character}`);
                    return new vscode.Location(
                        vscode.Uri.file(xmlPath),
                        new vscode.Position(statementPosition.line, statementPosition.character)
                    );
                }
            }
        }

        console.log(`No matching XML statement found for ${word}`);
        return undefined;
    }

    private async handleXmlFile(
        document: vscode.TextDocument,
        word: string,
        workspaceFolder: vscode.WorkspaceFolder
    ): Promise<vscode.Location | undefined> {
        // 从XML文件中获取namespace
        const namespace = this.getNamespace(document);
        if (!namespace) {
            console.log(`Could not determine namespace from XML file`);
            return undefined;
        }

        console.log(`Found namespace: ${namespace}`);

        // 构建可能的Java文件路径
        const possibleJavaPaths = this.getPossibleJavaPaths(workspaceFolder.uri.fsPath, namespace);
        console.log(`Searching in possible Java paths: ${possibleJavaPaths.join(', ')}`);

        // 在Java文件中查找对应的方法
        for (const javaPath of possibleJavaPaths) {
            if (fs.existsSync(javaPath)) {
                console.log(`Checking Java file: ${javaPath}`);
                const javaContent = fs.readFileSync(javaPath, 'utf8');
                const methodPosition = this.findMethodInJava(javaContent, word);
                if (methodPosition) {
                    console.log(`Found method at line ${methodPosition.line}, char ${methodPosition.character}`);
                    return new vscode.Location(
                        vscode.Uri.file(javaPath),
                        new vscode.Position(methodPosition.line, methodPosition.character)
                    );
                }
            }
        }

        console.log(`No matching Java method found for ${word}`);
        return undefined;
    }

    private getInterfaceName(document: vscode.TextDocument): string | undefined {
        const text = document.getText();
        // 匹配接口定义
        const interfaceMatch = /\binterface\s+(\w+)/.exec(text);
        if (interfaceMatch) {
            return interfaceMatch[1];
        }
        
        // 如果找不到接口定义，尝试从文件名获取
        const fileName = path.basename(document.fileName, '.java');
        if (fileName) {
            return fileName;
        }
        
        return undefined;
    }

    private getNamespace(document: vscode.TextDocument): string | undefined {
        const text = document.getText();
        // 匹配mapper的namespace属性
        const namespaceMatch = /namespace=["']([^"']+)["']/.exec(text);
        return namespaceMatch ? namespaceMatch[1] : undefined;
    }

    private getPossibleXmlPaths(workspacePath: string, interfaceName: string): string[] {
        // 常见的Mapper XML文件位置
        const commonPaths = [
            'src/main/resources/mapper',
            'src/main/resources/mybatis',
            'src/main/resources/mybatis/mapper',
            'src/main/resources',
            'src/resources/mapper',
            'src/resources',
            'resources/mapper',
            'mapper'
        ];

        // 处理多模块项目，搜索所有可能的模块
        const paths: string[] = [];
        const modules = this.findModules(workspacePath);
        
        for (const module of modules) {
            for (const commonPath of commonPaths) {
                // 检查完整的Mapper名称
                paths.push(path.join(module, commonPath, `${interfaceName}Mapper.xml`));
                paths.push(path.join(module, commonPath, `${interfaceName}.xml`));
                
                // 检查子目录
                const fullPath = path.join(module, commonPath);
                if (fs.existsSync(fullPath)) {
                    try {
                        const files = fs.readdirSync(fullPath);
                        for (const file of files) {
                            if (file.endsWith('.xml') && 
                                (file.includes(interfaceName) || file.toLowerCase().includes(interfaceName.toLowerCase()))) {
                                paths.push(path.join(module, commonPath, file));
                            }
                        }
                        
                        // 检查子目录
                        const subdirs = fs.readdirSync(fullPath, { withFileTypes: true })
                            .filter(dirent => dirent.isDirectory())
                            .map(dirent => dirent.name);
                            
                        for (const subdir of subdirs) {
                            const subdirPath = path.join(fullPath, subdir);
                            try {
                                const subfiles = fs.readdirSync(subdirPath);
                                for (const file of subfiles) {
                                    if (file.endsWith('.xml') && 
                                        (file.includes(interfaceName) || file.toLowerCase().includes(interfaceName.toLowerCase()))) {
                                        paths.push(path.join(module, commonPath, subdir, file));
                                    }
                                }
                            } catch (error) {
                                console.error(`Error reading subdirectory ${subdirPath}:`, error);
                            }
                        }
                    } catch (error) {
                        console.error(`Error reading directory ${fullPath}:`, error);
                    }
                }
            }
        }

        return paths;
    }

    private getPossibleJavaPaths(workspacePath: string, namespace: string): string[] {
        const javaPath = namespace.replace(/\./g, path.sep) + '.java';
        const paths: string[] = [];
        const modules = this.findModules(workspacePath);
        
        for (const module of modules) {
            // 常见的Java源文件位置
            paths.push(path.join(module, 'src', 'main', 'java', javaPath));
            paths.push(path.join(module, 'src', 'java', javaPath));
            paths.push(path.join(module, 'java', javaPath));
            
            // 搜索整个src目录
            const srcPath = path.join(module, 'src');
            if (fs.existsSync(srcPath)) {
                this.findJavaFilesRecursively(srcPath, namespace.split('.').pop() || '', paths);
            }
        }

        return paths;
    }
    
    private findJavaFilesRecursively(dir: string, className: string, results: string[]): void {
        try {
            const files = fs.readdirSync(dir, { withFileTypes: true });
            for (const file of files) {
                const fullPath = path.join(dir, file.name);
                if (file.isDirectory()) {
                    this.findJavaFilesRecursively(fullPath, className, results);
                } else if (file.name.endsWith('.java') && file.name.includes(className)) {
                    results.push(fullPath);
                }
            }
        } catch (error) {
            console.error(`Error searching directory ${dir}:`, error);
        }
    }

    private findModules(workspacePath: string): string[] {
        const modules = [workspacePath];
        
        try {
            // 读取根目录下的文件和文件夹
            const items = fs.readdirSync(workspacePath, { withFileTypes: true });
            
            for (const item of items) {
                if (item.isDirectory()) {
                    const modulePath = path.join(workspacePath, item.name);
                    
                    // 检查是否是Maven或Gradle模块
                    if (fs.existsSync(path.join(modulePath, 'pom.xml')) || 
                        fs.existsSync(path.join(modulePath, 'build.gradle')) ||
                        fs.existsSync(path.join(modulePath, 'build.gradle.kts'))) {
                        modules.push(modulePath);
                    }
                    
                    // 递归检查子模块
                    modules.push(...this.findModules(modulePath));
                }
            }
        } catch (error) {
            console.error(`Error finding modules in ${workspacePath}:`, error);
        }
        
        return modules;
    }

    private findStatementInXml(content: string, statementId: string): { line: number, character: number } | undefined {
        const lines = content.split('\n');
        const statementTypes = ['select', 'insert', 'update', 'delete'];
        
        // 处理可能的ID大小写不匹配问题
        const statementIdLower = statementId.toLowerCase();
        
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            
            // 检查是否是注释
            if (line.trim().startsWith('<!--')) {
                continue;
            }
            
            // 匹配任何Mybatis语句类型
            for (const type of statementTypes) {
                // 使用不区分大小写的搜索
                const idPattern = new RegExp(`id=["']([^"']*)["']`, 'i');
                const match = idPattern.exec(line);
                
                if (match && match[1].toLowerCase() === statementIdLower) {
                    return { line: i, character: match.index };
                }
            }
        }
        return undefined;
    }

    private findMethodInJava(content: string, methodName: string): { line: number, character: number } | undefined {
        const lines = content.split('\n');
        let inComment = false;
        
        // 处理可能的方法名大小写不匹配问题
        const methodNameLower = methodName.toLowerCase();
        
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            
            // 跳过多行注释
            if (line.includes('/*')) {
                inComment = true;
            }
            if (line.includes('*/')) {
                inComment = false;
                continue;
            }
            if (inComment) {
                continue;
            }
            
            // 跳过单行注释
            if (line.trim().startsWith('//')) {
                continue;
            }
            
            // 使用不区分大小写的搜索
            const methodPattern = new RegExp(`\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\(`, 'g');
            let methodMatch;
            
            while ((methodMatch = methodPattern.exec(line)) !== null) {
                if (methodMatch[1].toLowerCase() === methodNameLower) {
                    return { line: i, character: methodMatch.index };
                }
            }
        }
        return undefined;
    }
}